#! /usr/bin/env python
# coding: utf-8

import clases


def isInt( str ):
    ok = 1
    try:
        num = int(str)
    except ValueError:
        ok = 0
    return ok

def imprimirNodos( nodos ):
    print "Cantidad de nodos generados: " + str( len(nodos) )
    for p in nodos:
        print " -- NODO "+str(nodos[p].id) +" -- "
        print "entrantes:"
        print nodos[p].entrantes
        print "salientes:"
        print nodos[p].salientes


def obtenerTareasFinales(tareas):
    ConjuntoPrecedencias = []
    ConjuntoTareas = []
    for ind,t in tareas.iteritems():
        ConjuntoPrecedencias.extend(t.precedence)
        ConjuntoTareas.append(t.name)
    return set(ConjuntoTareas).difference(ConjuntoPrecedencias)



def cargarSalientes(tarea,nodos):
    """Busca el nodo que cumple con la precedencia requerida por la tarea.
       Si lo encuentra, carga en salientes a la tarea y devuelve True."""
    for i,nodo in nodos.iteritems():
        if set(tarea.precedence).issubset(nodo.precedenciaCumplida):
            nodo.salientes.append(tarea.name)
            return True
    return False

def ficticiasPrecedencias(tar,nodos,nuevoNodo):
    todo =  set([])
    for i,nodo in nodos.iteritems():
        tmp = set(tar.precedence).intersection(nodo.precedenciaCumplida)
        todo = todo.union(tmp)
        if len(tmp) > 0:
            nodo.salientes.append('Fict ' + str(nodo.id))
            nuevoNodo.entrantes.append('Fict ' + str(nodo.id))
    return todo
def ficticiasAuxiliares(nodos):
    ficticios = []
    
    for i,nodoA in nodos.iteritems():
        for j,nodoB in nodos.iteritems():
            if (i != j) and (len(nodoA.salientes) >= 2)  and (len(nodoB.entrantes) >= 2)  and (not nodoA.terminado and not nodoB.terminado):
                tmp2 = list(set(nodoA.salientes).intersection(nodoB.entrantes))
                elementos = len(tmp2)
                if elementos >= 2:
                    for ind in range(elementos - 1):
                        nodoFicticio = clases.Nodo()
                        nodoFicticio.entrantes.append(tmp2[ind])
                        nodoFicticio.salientes.append('Fict ' + str(nodoFicticio.id))
                        nodoFicticio.terminado = True
                        nodoB.terminado = True
                        nodoA.terminado = True
                        nodoB.entrantes.append('Fict ' + str(nodoFicticio.id) )
                        # se agrega [] recordar que tmp2[ind] es un elemento.
                        nodoB.entrantes = list(set(nodoB.entrantes).difference([ tmp2[ind] ]))
                        ficticios.append(nodoFicticio)
    for new in ficticios:
        nodos[new.id] = new


def crearNodos(tareas):
    nodos = {}
    ConjuntoFinales = obtenerTareasFinales(tareas)
    inicial = clases.Nodo("INICIAL")
    inicial.temprana = 0
    nodos[inicial.id] = inicial
    l = tareas.items()
    # que groso es lambda, lisp snif snif
    l.sort(lambda x,y: len(x[1].precedence) - len(y[1].precedence) )

    for ind,tar in l:
	print tar.name
        if len(tar.precedence) == 0:
            inicial.salientes.append(tar.name)
        else:
            if not cargarSalientes(tar,nodos):
                nuevoNodo =  clases.Nodo()
                tmp = ficticiasPrecedencias(tar,nodos,nuevoNodo)
                nuevoNodo.entrantes.extend(set(tar.precedence).difference( tmp ))
                nuevoNodo.salientes.append(tar.name)
                nuevoNodo.precedenciaCumplida.extend(tar.precedence)
                nodos[nuevoNodo.id] = nuevoNodo
    

    ultimoNodo = clases.Nodo("Ultimo nodo")
    for fin in list(ConjuntoFinales):
        ultimoNodo.entrantes.append(fin)
    nodos[ultimoNodo.id] = ultimoNodo


    ficticiasAuxiliares(nodos)

    return nodos

def dibujarNodos(nodos):
        import pydot
        l = nodos.items()
        l.sort(lambda x,y: x[1].id <= y[1].id)

        g=pydot.graph_from_edges([]) 
        g.set_type('digraph')
        for i1,n1 in l:
            test = pydot.Node(n1.id)
            g.add_node(test)
        for i1,n1 in l:
            for i2,n2 in l:
                if (i1 != i2):
                    inter = list(set(n1.entrantes).intersection(n2.salientes))
                    for j in inter:
                        e = pydot.Edge(n2.id,n1.id)
                        e.set_label(j)
                        g.add_edge( e )

        g.write_jpeg('grafico.jpg', prog='dot') 


if __name__ == "__main__":
    tareas = {}

    while True:
        menu = name = raw_input("Nombre tarea (Usa letras mayúsculas que queda lindo,'0' para terminar): ")
        if (isInt(menu)) and int(menu) == 0: break;
        duration = raw_input("Duración: ")
        precedence = raw_input("Precedencias (ex: A,B,C,D) o bien -: ")
        if precedence != '-':
            precedence = precedence.split(",")
        else:
            precedence = []
            
        t = clases.Tarea(name,duration,precedence)
        tareas[t.name] = t

    if len(tareas) > 0:
        nodos = crearNodos(tareas)
        imprimirNodos(nodos)
        dibujarNodos(nodos)

    else:
        print "No se cargaron tareas."
